package com.sunbim.rsrv.service.impl;

import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sunbim.rsrv.common.exception.RequestException;
import com.sunbim.rsrv.common.exception.ServiceException;
import com.sunbim.rsrv.mapper.StorageMapper;
import com.sunbim.rsrv.mapper.UserMapper;
import com.sunbim.rsrv.params.user.UserChangePasswordParams;
import com.sunbim.rsrv.params.user.UserLoginParams;
import com.sunbim.rsrv.pojo.Storage;
import com.sunbim.rsrv.pojo.User;
import com.sunbim.rsrv.service.StorageService;
import com.sunbim.rsrv.service.UserService;
import com.sunbim.rsrv.util.password.Salt;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author yuhui
 * @since 2021-12-30
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Autowired
    UserMapper userMapper;
    @Autowired
    StorageService storageService;
    @Autowired
    StorageMapper storageMapper;

    @Override
    public Map<String, Object> login(UserLoginParams params) {
        // 判断该用户名是否存在
        boolean usernameExist = userMapper.usernameExist(params.username);
        if (!usernameExist) throw new ServiceException("用户名: " + params.username + " 不存在");
        // 校验密码是否正确
        String encodePassword = userMapper.getPasswordByUsername(params.username);
        boolean check = Salt.check(params.username, encodePassword, params.password);
        if (!check) throw new ServiceException("密码错误,请重新输入");
        // 获取用户信息
        HashMap<String, Object> data = userMapper.getUserByUsername(params.username);
        // Satoken 登录,并更新最后登录时间
        StpUtil.login(data.get("id"), new SaLoginModel().setIsLastingCookie(true));
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        data.put(tokenInfo.getTokenName(), tokenInfo.getTokenValue());
        return data;
    }

    @SneakyThrows
    @Transactional
    @Override
    public void register(User user, MultipartFile file) {
        // 判断该用户名是否已存在
        boolean usernameExist = userMapper.usernameExist(user.getUsername());
        if (usernameExist) throw new RequestException("用户名: " + user.getUsername() + " 已存在");

        // md5加盐加密
        String encodePassword = Salt.encode(user.getUsername(), user.getPassword());
        user.setPassword(encodePassword);
        // 插入到数据库
        userMapper.insert(user);
        // 保存图片
        storageService.upload(null, user.getId(), null, "icon", "", file);
    }

    /**
     * 用户更新
     *
     * @param user
     * @param file 项目封面图
     */
    @Override
    public void updateUser(User user, MultipartFile file) {
        User user1 = userMapper.selectById(user.getId());
        if (user1 == null) throw new RequestException("用户不存在");
        // md5加盐加密
        if (!StringUtils.isAnyEmpty(user.getUsername(), user.getPassword())) {
            String encodePassword = Salt.encode(user.getUsername(), user.getPassword());
            user.setPassword(encodePassword);
        }
        // 插入到数据库
        userMapper.updateById(user);
        // 保存图片
        if (file != null) {
            Storage storage = new Storage();
            storage.setUserId(user.getId());
            storage.setStorageType("icon");
            Storage first = CollectionUtil.getFirst(storageMapper.selectList(new QueryWrapper<>(storage)));
            if (first != null) {
                log.info("更新项目封面");
                storageService.update(first.getId(), user.getId(), null, "icon", "", file);
            } else {
                log.info("项目封面不存在，保存新的封面");
                storageService.upload(null, user.getId(), null, "icon", "", file);
            }
        }

    }

    @Override
    public void logout() {
        StpUtil.logout();
    }

    @Override
    public void updateUser(User user) {
        boolean b = userMapper.usernameExistExcludeOwner(user.getId(), user.getUsername());
        if (b) throw new RequestException("用户名: " + user.getUsername() + " 已存在");
        userMapper.updateById(user);
    }

    @Override
    public void changePassword(UserChangePasswordParams params) {
        // 获取登录用户的id, 获取该用户信息
        int loginId = StpUtil.getLoginIdAsInt();
        User user = userMapper.selectById(loginId);

        // 校验旧密码是否正确
        String encodeOldPassword = Salt.encode(user.getUsername(), params.oldPassword);
        if (!encodeOldPassword.equals(user.getPassword())) throw new RequestException("密码不正确");
        // 新密码加密,更新密码
        String encodeNewPassword = Salt.encode(user.getUsername(), params.newPassword);
        user.setPassword(encodeNewPassword);
        userMapper.updateById(user);
        // 更新后退出登录状态
        StpUtil.logout();
    }

    @Override
    public List<Map<String, Object>> getAllExcludeAdmin() {
        return userMapper.getAllExcludeAdmin();
    }

    @Transactional
    @Override
    public void deleteUser(int id) {
        int count = userMapper.deleteById(id);
        if (count == 0) throw new RequestException("该用户不存在");
        storageService.deleteAllByUserId(id);
        StpUtil.logout(id);
    }

    @Override
    public Map<String, Object> getUserById(Object loginId) {
        return userMapper.getUserById(loginId);
    }

    @Override
    public List<Map<String, Object>> searchByProjectName(String keyword) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.ne("user_role", "admin");
        wrapper.like("project_name", keyword);
        wrapper.select("id", "nickname", "user_role", "region", "project_name", "project_desc", "project_geo", "create_time", "update_time");
        return userMapper.selectMaps(wrapper);
    }
}
